/*
*
* METROVIEW
*
*/

// IMPORT LIBRARIES

import processing.pdf.*;
import controlP5.*;
import org.gicentre.utils.move.*;
import org.gicentre.utils.colour.*;
import org.gicentre.utils.spatial.*;

// DECLARE GLOBAL VARIABLES

ZoomPan zoomer;
ControlP5 controlP5;
PDFUI pdfui;
MMUI mmui;
StaticUI sui;
ScaleUI scal;
ModeSelectorUI msui;
NHoodInfoUI nhui;
PDFMaker pdfm;
Poll[] polls;
float[][] maxMins;
int dMode;            
color dFil;    
color noDataFil;    
color strok; 
DModeManager dmm;
Ellipsoid wgs84;
UTM utmConverter;
PVector localOrigin;
float localWidth, localHeight;
float sw;
PFont pdfExportFontSmall, pdfExportFontLarge;

// -----------------------------------------------
// SETUP
// -----------------------------------------------

void setup() {
  
  // CREATE WINDOW
  
  size(612, 600); // optimized for display on jeemang.ca
  background(240);
   
  // READ DATA
  
  // load font
  pdfExportFontSmall = createFont("LetterGothicStd-Bold", 9, true);
  pdfExportFontLarge = createFont("LetterGothicStd-Bold", 15, true);
  //println(PGraphicsPDF.listFonts());
  
  // read kml file
  KMLReader kmlr = new KMLReader(this);
  
  // read neighbourhood kml and csv files
  String[][] kmlData = kmlr.readKML();
  String[][] electionData = kmlr.readElectionInfo();
//  String[][] censusData = kmlr.readNInfo();
//  String[][] otherData = kmlr.readNOtherInfo();
  
  // ASSIGN GLOBAL VARIABLES
  
  // create UTM converter to convert lat/long coordinates to UTM, and use it create local origin
  wgs84 = new Ellipsoid(Ellipsoid.WGS_84);  // WGS-84 is apparently the most commonly used ellipsoid for projections of this type
  utmConverter = new UTM(wgs84, 12, 'U');   // Edmonton's UTM zone is 12U
  PVector originll = new PVector(-113.91, 53.36); // this controls the starting position
  localOrigin = utmConverter.latLongToUTM(originll);
  
  // set local width and height
  localWidth = 45000; // units are in meters as per UTM specifications; this controls starting "zoom"
  localHeight = localWidth * height / width;
  
  // create neighbourhood objects and calculate metrics
  PollMaker pm = new PollMaker(kmlData, electionData);
  polls = pm.makePolls();     
  
  // create drawing mode manager and set startup drawing mode
  dmm = new DModeManager(polls);
  dmm.setDMode(0);
  
  // create various UI components
  pdfm = new PDFMaker();                                                      // controls PDF creation in sketch
  controlP5 = new ControlP5(this);                                            // "parent" UI object
  sui = new StaticUI(controlP5, this);                                        // object encapsulating static UI components
  scal = new ScaleUI(controlP5, this, 10, 44, 20, 60);                        // controls falsecolour scale bar
  //msui = new ModeSelectorUI(controlP5, this, dmm, 6, 187, 225, 300);          // controls drawing mode selector
  msui = new ModeSelectorUI(controlP5, this, dmm, 6, 171, 169, 15);
  nhui = new NHoodInfoUI(controlP5, 6, 124, 225, 43);                         // "neighbourhood info" box that displays neighbourhood info based on mouse position
  pdfui = new PDFUI(controlP5, this, 79, 78, 80, 15);                         // create pdf button
  mmui = new MMUI(controlP5, this, 79, 98, 80, 15);                         // create max/min mode toggle button
  zoomer = new ZoomPan(this);                                                 // object for zooming and panning 
  zoomer.setZoomMouseButton(PConstants.RIGHT);                                // set mouse button for zooming/panning
  
  // SET GRAPHIC PARAMETERS
  
  smooth();
  sw = 0.3;
  strokeWeight(sw);
  dFil = color(200, 200, 200);     // "default" fill
  noDataFil = color(128, 128, 128);    // "no data" fill -- used to fill neighbourhoods when the neighbourhood has no data
  strok = color(75, 75, 75, 100);     // "default" stroke
   
}

// -----------------------------------------------
// DRAW
// -----------------------------------------------

void draw() {
  
  // CHECK PDF RECORDING
  pdfm.recordOn();
  
  // SET UP ZOOMING/PANNING
  
  // draw background
  background(245); 
  
  // store a copy of unzoomed screen transformation
  pushMatrix();
  
  // Enable the zooming/panning
  zoomer.transform();
  
  // PDF RECORDING
  
  // for some reason transforms applied by ZoomPan object
  // don't register with the pdf writing library. Therefore, if
  // writing pdf, apply these manually
  if(pdfm.checkRecord()) {

    pushMatrix();
    
    // extract ZoomPan transform vector and scale
    PVector orig = new PVector(0, 0); 
    PVector translation = zoomer.getCoordToDisp(orig);
    float s = (float) zoomer.getZoomScale();
    // re-apply transforms and adjust strokeWeight
    scale(s);
    translate(translation.x/s, translation.y/s);
    sw = sw / s;
    strokeWeight(sw);
  } // if
  
  // APPLY ROTATIONAL CORRECTION FOR UTM PLOTTING
  
  // rotate neighbourhoods to align lat/long w/ horizontal/vertical
  pushMatrix();
  float rot = -PI/80;
  rotate(rot);
  
  // DRAW DYNAMIC OBJECTS
  
  // get mouse coordinates, accounting for zoom and pan
  PVector poinNR = zoomer.getMouseCoord();
  // rotate this point around z axis (getMouseCoord accounts for transformations
  // made by the zoomer object, but not the corrective rotation applied above)
  PVector poin = new PVector( (cos(-rot) * poinNR.x - sin(-rot) * poinNR.y), (sin(-rot) * poinNR.x + cos(-rot) * poinNR.y) );
  
  // hide objects updated when mouse is over neighbourhoods, so
  // they don't display if the mouse isn't over any neighbourhoods
  nhui.hideDynamic();
  
  // draw neighbourhoods and check if mouse is over each neighbourhood
  for(int i = 0; i < polls.length; i++) {
    polls[i].draw(dmm);
    polls[i].checkMouseOver(poin, nhui, dmm);
  }
  
  // PDF RECORDING
  
  // if pdf recording is on, pop off pdf transformation and restore strokeweight
  if(pdfm.checkRecord()) {
    popMatrix();
    
    float s = (float) zoomer.getZoomScale();
    sw = sw * s;
    strokeWeight(sw);
  }
  
//  // if pdf recording is on, switch off, and restore other settings to
//  // non-pdf-writing levels
//  if(pdfm.checkRecord()) {
//    
//    popMatrix();
//    popMatrix();
//    sui.draw(true);
//    scal.draw(dmm, true);
//
//    
//    float s = (float) zoomer.getZoomScale();
//    sw = sw * s;
//    strokeWeight(sw);
//    
//    pdfm.recordOff();
//  }
  
  // ROTATIONAL CORRECTION FOR UTM PLOTTING
  
  popMatrix(); // rotation
  
  // DRAW STATIC OBJECTS
  
  // Restore the unzoomed screen transformation.
  popMatrix();    
  
  // draw static UI componenets, checking if pdf writing is on.
  // If so, write UI components for pdf export, and turn off pdf recording
  if(pdfm.checkRecord()) {
    sui.draw(true);
    scal.draw(dmm, true);

    pdfm.recordOff();
  } else {
    sui.draw(false);
    scal.draw(dmm, false);
    msui.draw();
    nhui.drawStatic();
    pdfui.draw();
    mmui.draw(); 
  } // if 
        
//  // draw static UI components 
//  sui.draw(false);
//  scal.draw(dmm, false);
//  msui.draw();
//  nhui.drawStatic();
//  pdfui.draw();
//  mmui.draw();  
}

// -----------------------------------------------
// CONTROLP5 EVENT LISTENER
// -----------------------------------------------

// ------------------------------------
// controlEvent
// this is a "standard" controlP5 method that
// is used to listen for events
// -------------------------------------
void controlEvent(ControlEvent event) {
  // check type of event
  if(event.isController()) {
    if(event.controller().id() == 1) {    // events coming from ModeSelector
      // note: right now, this currently produces 2 events: one from the ListButton, and 
      // one from the MultiListButton. This seems weird, but it's how things happen in the
      // multiList example, so I'll leave it for now
      dmm.setDMode( (int) event.controller().value() );
    } else if(event.controller().id() == 2) {  // events coming from "export pdf" button
      String path = selectOutput();
      if(path != null) {
        pdfm.switchRecord();
        pdfm.path = path;
      }
    } else if(event.controller().id() == 3) {  // events coming from scale mode button
      mmui.switchMMMode(dmm);
    } // else if
  } // if
  
} // controlP5 event listener
